using System.Linq;
using System.Threading;
using System.Reflection;
using System.Collections.Generic;
using log4net;

namespace Parallel
{
    public class ParallelExecutable<T> where T : class
    {
        private readonly MethodInfo _method;
        private readonly T _item;
        private readonly IEnumerable<T> _items = new List<T>();
        private readonly ManualResetEvent _mre;
        readonly ILog _logger = LogManager.GetLogger(typeof(ParallelExecutable<T>));

        public ParallelExecutable(MethodInfo method, T item, ManualResetEvent mre)
        {
            _method = method;
            _item = item;
            _mre = mre;
        }

        public ParallelExecutable(MethodInfo method, IEnumerable<T> items, ManualResetEvent mre)
        {
            _method = method;
            _items = items;
            _mre = mre;
        }

        public void Execute()
        {
            _logger.Info("About to start parallel executable");

            if (_item != null)
                InvokeExecutable();

            if (_items.Count() > 0)
                InvokeSerialExecutables();

            _mre.Set();
        }

        private void InvokeExecutable()
        {
            _method.Invoke(_item, null);
        }

        private void InvokeSerialExecutables()
        {
            foreach (var item in _items)
            {
                _method.Invoke(item, null);
            }
        }
    }
}